package db

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"sort"
	"strconv"
	"strings"
	"sync"
	"ulcdkey/tool"
)

// 游戏表缓存
type GameCache struct {
	Data map[int]*Game
	Lock sync.RWMutex
}

func NewGameCache() *GameCache {
	var nMap = new(GameCache)
	nMap.Data = make(map[int]*Game)
	return nMap
}

// 更新游戏缓存
func RefreshGameCache() (err error) {
	temp := make(map[int]*Game)

	var games = new(Game)
	as, err := games.GetGameList()
	if err != nil {
		return
	}
	for _, a := range as {
		temp[a.Id] = a
	}

	GameCacheMap.Lock.Lock()
	defer GameCacheMap.Lock.Unlock()
	GameCacheMap.Data = temp
	return
}

// 读取游戏缓存
func ReadGameCacheById(gameId int) *Game {
	GameCacheMap.Lock.RLock()
	defer GameCacheMap.Lock.RUnlock()
	return GameCacheMap.Data[gameId]
}

/* -------------------------------------------------------------- */

// 获取所有游戏列表
func (this *Game) GetGameList() (as []*Game, err error) {

	rows, err := db.Query(`SELECT a.id, a.gameCode, a.gameName, a.icon, IFNULL(b.path,"") as path, a.createUserId, a.updateUserId, a.createTime FROM game a LEFT JOIN file b ON a.icon = b.id ORDER BY id;`)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		a := new(Game)
		err = rows.Scan(&a.Id, &a.GameCode, &a.GameName, &a.IconId, &a.IconUrl, &a.CreateUserId, &a.UpdateUserId, &a.CreateTime)
		if err != nil {
			return
		}
		a.CreateUserName = UserList[a.CreateUserId].Name
		a.UpdateUserName = UserList[a.UpdateUserId].Name

		as = append(as, a)
	}
	return
}

// 获取用户权限的游戏列表
func (this *Game) GetUserAuthGameList(uid int) (as []*Game, err error) {
	user := UserList[uid]
	role := RolesList[user.RoleId]
	gameAuthArr := strings.Split(role.GameAuth, ",")

	if role.GameAuth == "all" {
		// 所有游戏
		GameCacheMap.Lock.RLock()
		for _, game := range GameCacheMap.Data {
			game.CreateUserName = UserList[game.CreateUserId].Name
			game.UpdateUserName = UserList[game.UpdateUserId].Name

			as = append(as, game)
		}
		GameCacheMap.Lock.RUnlock()

	} else {
		for _, gameAuthIdStr := range gameAuthArr {
			var gameAuthId int
			gameAuthId, err = strconv.Atoi(gameAuthIdStr)
			if err != nil {
				return
			}

			game := ReadGameCacheById(gameAuthId)
			if game != nil {
				game.CreateUserName = UserList[game.CreateUserId].Name
				game.UpdateUserName = UserList[game.UpdateUserId].Name

				as = append(as, game)
			}

		}
	}

	// 按id排序
	sort.SliceStable(as, func(i, j int) bool {
		return as[i].Id < as[j].Id
	})

	return
}

//// 根据平台获取游戏列表
//func (this *Game) GetGameListByPlatform() (as []*Game, err error) {
//	rows, err := db.Query(`
//SELECT
//	a.id,
//	a.gameCode,
//	a.gameName,
//	a.icon,
//	b.path,
//	a.createUserId,
//	a.updateUserId,
//	a.createTime
//FROM
//	(
//		SELECT
//			id,
//			gameCode,
//			gameName,
//			icon,
//			createUserId,
//			updateUserId,
//			createTime
//		FROM
//			game
//
//	) a
//LEFT JOIN file b ON a.icon = b.id
//ORDER BY
//	id;`)
//	if err != nil {
//		return
//	}
//	defer rows.Close()
//	for rows.Next() {
//		a := new(Game)
//		err = rows.Scan(&a.Id, &a.GameCode, &a.GameName, &a.IconId, &a.IconUrl, &a.CreateUserId, &a.UpdateUserId, &a.CreateTime)
//		if err != nil {
//			return
//		}
//		a.CreateUserName = UserList[a.CreateUserId].Name
//		a.UpdateUserName = UserList[a.UpdateUserId].Name
//
//		as = append(as, a)
//	}
//	return
//}

// 新增游戏
func (this *Game) AddGame(info *tool.VisitUserInfo) (err error) {
	var isExistGameCode int
	err = db.QueryRow("select count(1) from game where gameCode = ?", this.GameCode).Scan(&isExistGameCode)
	if err != nil {
		log.Println("db.AddGame error1,err=", err)
		return
	}

	if isExistGameCode != 0 {
		return errors.New("gameCode已经存在，请重新输入")
	}

	row, err := db.Exec("insert into game (gameCode,gameName, icon,createUserId,updateUserId) values (?,?,?,?,?)", this.GameCode, this.GameName, this.IconId, this.CreateUserId, this.UpdateUserId)
	if err != nil {
		log.Println("db.AddGame error2,err=", err)
		return
	}

	int64s, err := row.LastInsertId()
	if err != nil {
		log.Println("db.AddGame error3,err=", err)
		return
	}
	this.Id = int(int64s)

	// 创建 cdk 清单表
	mysqlTableName := fmt.Sprintf("ulcdkey_cdk.cdk_%s", this.GameCode)
	createSql := fmt.Sprintf(
		`
  CREATE TABLE IF NOT EXISTS %s (
  id int(11) NOT NULL AUTO_INCREMENT,
  cdkTypeId int(11) NOT NULL,
  cdkey varchar(40) COLLATE utf8_bin NOT NULL,
  status int(3) NOT NULL COMMENT '0 可使用 1 已使用 2 已生成但不可使用',
  canUseTimes int(11) NOT NULL DEFAULT '0',
  bAll int(11) NOT NULL DEFAULT '0',
  invalidTime timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY cdkTypeId (cdkTypeId) USING BTREE
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
			`, mysqlTableName)
	// 创建表
	_, err = db.Exec(createSql)
	if err != nil {
		log.Println("db.AddGame error4,err=", err)
		return
	}

	// 创建 cdk 使用表
	mysqlUserTableName := fmt.Sprintf("ulcdkey_cdkuse.cdkuse_%s", this.GameCode)
	createUseSql := fmt.Sprintf(
		`
  CREATE TABLE IF NOT EXISTS %s (
  id int(11) NOT NULL AUTO_INCREMENT,
  bUserId varchar(255) COLLATE utf8_bin NOT NULL COMMENT '使用者id',
  bUseTime varchar(128) COLLATE utf8_bin NOT NULL COMMENT '使用时间',
  cdkey varchar(40) COLLATE utf8_bin NOT NULL,
  cdkTypeId int(11) NOT NULL,
  invalidTime timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY cdkTypeId (cdkTypeId) USING BTREE
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
			`, mysqlUserTableName)
	// 创建mysql cdk使用表
	_, err = db.Exec(createUseSql)
	if err != nil {
		log.Println("db.AddGame error5,err=", err)
		return
	}

	// 更新缓存
	err = RefreshGameCache()
	if err != nil {
		log.Println("db.AddGame error6,err=", err)
		return
	}

	// 记录日志
	b, _ := json.Marshal(this)
	serverLog := &ServerLog{UserId: info.Uid, UserName: info.UserName, ActionType: LogActionType.Add, Module: "游戏管理", OldContent: "", NewContent: string(b)}
	serverLog.RecordLog()
	return
}

// 更新游戏
func (this *Game) UpdateGame(info *tool.VisitUserInfo) (err error) {
	old, err := this.GetGameById(this.Id)
	if err != nil {
		return
	}

	_, err = db.Exec("update game set gameName = ?,icon = ?,updateUserId = ? where id = ?", this.GameName, this.IconId, this.UpdateUserId, this.Id)
	if err != nil {
		return
	}

	// 更新缓存
	err = RefreshGameCache()
	if err != nil {
		return
	}

	// 记录日志
	nb, _ := json.Marshal(this)
	ob, _ := json.Marshal(old)
	serverLog := &ServerLog{UserId: info.Uid, UserName: info.UserName, ActionType: LogActionType.Update, Module: "游戏管理", OldContent: string(ob), NewContent: string(nb)}
	serverLog.RecordLog()
	return
}

// 删除游戏
func (this *Game) DelGame(info *tool.VisitUserInfo) (err error) {

	old, err := this.GetGameById(this.Id)
	if err != nil {
		return
	}

	_, err = db.Exec("delete from game where id = ?", this.Id)
	if err != nil {
		return
	}

	// 更新缓存
	err = RefreshGameCache()
	if err != nil {
		return
	}

	// 记录日志
	ob, _ := json.Marshal(old)
	serverLog := &ServerLog{UserId: info.Uid, UserName: info.UserName, ActionType: LogActionType.Delete, Module: "游戏管理", OldContent: string(ob), NewContent: ""}
	serverLog.RecordLog()

	return
}

// 根据id获取游戏
func (this *Game) GetGameById(id int) (res *Game, err error) {
	res = new(Game)
	err = db.QueryRow(`
SELECT
    a.id,
    a.gameCode,
	a.gameName,
    a.icon,
	b.path,
	a.createUserId,
	a.updateUserId,
	a.createTime
FROM
	(
		SELECT
		    id,
		  	gameCode,
			gameName,
			icon,
			createUserId,
			updateUserId,
			createTime
		FROM
			game
		WHERE
			id = ?
	) a
LEFT JOIN file b ON a.icon = b.id limit 1
`, id).Scan(&res.Id, &res.GameCode, &res.GameName, &res.IconId, &res.IconUrl, &res.CreateUserId, &res.UpdateUserId, &res.CreateTime)
	return
}
